#ifndef B2D_STREAM_H
#define B2D_STREAM_H

#include "IUncopyable.h"

NS_B2D_BEGIN


////////////////////////////////////////////////////////////////////////////////////////////////////
/// \brief	Access mode.
////////////////////////////////////////////////////////////////////////////////////////////////////
enum class B2D_API AccessMode
{
	READ		= 1,
	WRITE		= 2,
	READ_WRITE	= READ | WRITE
};

////////////////////////////////////////////////////////////////////////////////////////////////////
/// \brief	Abstract base class for all streams.
////////////////////////////////////////////////////////////////////////////////////////////////////
class B2D_API Stream
	: public IUncopyable
{
protected:
	string mName;
	size_t mSize;
	AccessMode mAccessMode;
	bool mIsOpen;

public:
	Stream(void);
	virtual ~Stream(void);

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Gets the size of the stream in bytes.
	///
	/// \return	The size.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	size_t getSize(void) const { return mSize; }
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Gets access mode.
	///
	/// \return	The access mode.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	AccessMode getAccessMode(void) const { return mAccessMode; }
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Query if this stream is open.
	///
	/// \return	true if open, false if not.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	bool isOpen(void) const { return mIsOpen; }


	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Opens the stream in given mode.
	///
	/// \param	mode	The mode.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual void open(AccessMode mode);
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Closes this stream.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual void close(void);

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Read the given number of bytes to the output buffer.
	/// 		Returns the number bytes read.
	///
	/// \param [out]	output	If non-null, the output.
	/// \param	size		  	The size to read.
	///
	/// \return	The number of bytes read
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual size_t read(void* output, size_t size);
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Write the given number of bytes from the input buffer.
	/// 		Returns the number of bytes written.
	///
	/// \param	input	The input for writting.
	/// \param	size 	The size of data to write.
	///
	/// \return	The number of bytes written.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual size_t write(const void* input, size_t size);
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Skip the given number of bytes and get the new position.
	///
	/// \param	size	The number of bytes to skip.
	///
	/// \return	The new position.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual size_t skip(size_t size);
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Go to given offset from the start of the file and return the current position.
	///
	/// \param	offset	The position to seek.
	///
	/// \return	The new position.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual size_t seek(size_t offset);

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Gets the current position.
	///
	/// \return	The position.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual size_t getPosition(void) const = 0;
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Check if we have reached the end.
	///
	/// \return	true if eof, false if not.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual bool isEOF(void) const;

private:

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Opens stream implementation.
	///
	/// \param	mode	The mode.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual void openImpl(AccessMode mode) = 0;
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Close stream implementation.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual void closeImpl(void) = 0;
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Seek implementation.
	///
	/// \param	offset	The offset.
	///
	/// \return	New position.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual size_t seekImpl(size_t offset) = 0;
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Skip implementation.
	///
	/// \param	size	The number of bytes.
	///
	/// \return	New position.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual size_t skipImpl(size_t size) = 0;
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Read implementation.
	///
	/// \param [out]	output	If non-null, the output.
	/// \param	size		  	The size to read.
	///
	/// \return	The new position.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual size_t readImpl(void* output, size_t size) = 0;
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Write implementation.
	///
	/// \param	input	The input.
	/// \param	size 	The input size.
	///
	/// \return	The current position.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual size_t writeImpl(const void* input, size_t size) = 0;
};
typedef std::unique_ptr<Stream> StreamPtr;
typedef std::shared_ptr<Stream> SharedStreamPtr;

NS_B2D_END

#endif